package com.s7.widget.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Scroller;

import com.s7.widget.R;
import com.s7.widget.utils.LinearGradient;

import java.text.Format;
import java.util.ArrayList;
import java.util.List;

/**
 * 滚轮选择器
 * @param <T>
 */
public class WheelPicker<T> extends View {

    /**
     * 数据集合
     */
    private List<T> mDatas;

    private Format mDataFormat;

    /**
     * 未选择Item的Text的颜色、大小、画笔
     */
    @ColorInt
    private int mUnselectedColor = 0xFF333333;
    private int mUnselectedSize = 38;

    /**
     * 未选择Item的Text大小 相对于 选中的Item的Text大小 的百分比（mUnselectedSize / mSelectedSize）
     */
    private float mUnselectedPercent = (float) 0.8;

    /**
     * 字体渐变，开启后越靠近边缘，字体越模糊
     */
    private boolean mIsGradual = true;

    /**
     * 选中的Item的Text颜色、大小、画笔
     */
    @ColorInt
    private int mSelectedColor = 0xFF33AAFF;
    private int mSelectedSize = 50;

    /**
     * 画笔
     * 控件幕布、未选择Text、选择Text、指示器Text
     */
    private Paint mPaint, mTextPaint, mSelectedPaint, mIndicatorPaint;

    /**
     * 指示器（会在中心文字后边多绘制一个文字）
     * 指示器文字、颜色、大小、画笔
     */
    private String mIndicator;
    @ColorInt
    private int mIndicatorColor = 0xFF33AAFF;
    private int mIndicatorSize = 40;

    /**
     * 指示器X轴
     */
    private int mIndicatorDrawX = 0;

    /**
     * 最大的一个Item的文本的宽高
     */
    private int mTextMaxWidth = 0, mTextMaxHeight = 0;

    /**
     * 显示未选中的Item条数（所有条数 = mVisibleNumber * 2 + 1）
     */
    private int mVisibleNumber = 2;

    /**
     * Item高度
     */
    private int mItemHeight;

    /**
     * 当前的Item的位置(默认位置)
     */
    private int mCurrentPosition = 0;

    /**
     * 是否将中间的Item放大(选中的)
     */
    private boolean mIsZoom = true;

    /**
     * 是否显示幕布，中央Item会遮盖一个颜色
     */
    private boolean mIsCurtain = true;

    /**
     * 幕布颜色
     */
    @ColorInt
    private int mCurtainColor = 0xFFFFFFFF;

    /**
     * 是否显示幕布的边框
     */
    private boolean mIsCurtainBorder = true;

    /**
     * 幕布边框的颜色
     */
    @ColorInt
    private int mCurtainBorderColor = 0xFF33AAFF;

    /**
     * 整个控件的可绘制面积
     */
    private Rect mDrawnRect;

    /**
     * 中心被选中的Item的坐标矩形
     */
    private Rect mSelectedRect;

    /**
     * 第一个Item的绘制Text的坐标（中心坐标）
     */
    private int mFirstItemDrawX, mFirstItemDrawY;

    /**
     * 中心的Item绘制text的Y轴坐标
     */
    private int mCenterItemDrawnY;

    private Scroller mScroller;

    private int mTouchSlop;

    /**
     * 该标记的作用是，令mTouchSlop仅在一个滑动过程中生效一次。
     */
    private boolean mTouchSlopFlag;

    private VelocityTracker mTracker;

    private int mTouchDownY;

    /**
     * Y轴Scroll滚动的位移
     */
    private int mScrollOffsetY;

    /**
     * 最后手指Down事件的Y轴坐标，用于计算拖动距离
     */
    private int mLastDownY;

    /**
     * 是否循环读取数据
     */
    private boolean mIsCyclic = false;

    /**
     * 最大可以Fling的距离
     */
    private int mMaxFlingY, mMinFlingY;

    /**
     * 滚轮滑动时的最小/最大速度
     */
    private int mMinimumVelocity = 50, mMaximumVelocity = 12000;

    /**
     * 是否是手动停止滚动
     */
    private boolean mIsAbortScroller;

    private LinearGradient mLinearGradient;

    private Handler mHandler = new Handler();

    private OnWheelChangeListener<T> mOnWheelChangeListener;

    private Runnable mScrollerRunnable = new Runnable() {
        @Override
        public void run() {

            if (mScroller.computeScrollOffset()) {

                mScrollOffsetY = mScroller.getCurrY();
                postInvalidate();
                mHandler.postDelayed(this, 16);
            }
            if (mScroller.isFinished() || (mScroller.getFinalY() == mScroller.getCurrY()
                    && mScroller.getFinalX() == mScroller.getCurrX())) {

                if (mItemHeight == 0) {
                    return;
                }
                int position = -mScrollOffsetY / mItemHeight;
                position = fixItemPosition(position);
                if (mCurrentPosition != position) {
                    mCurrentPosition = position;
                    if (mOnWheelChangeListener == null) {
                        return;
                    }
                    mOnWheelChangeListener.onWheelSelected(mDatas.get(position), position);
                }
            }
        }
    };

    public WheelPicker(Context context) {
        super(context);
        init(context);
    }

    public WheelPicker(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context, attrs);
        init(context);
    }

    public WheelPicker(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        init(context);
    }

    private void init(Context context) {
        mDatas = new ArrayList<>();
        initPaint();
        mLinearGradient = new LinearGradient(mUnselectedColor, mSelectedColor);
        mDrawnRect = new Rect();
        mSelectedRect = new Rect();
        mScroller = new Scroller(context);

        ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = configuration.getScaledTouchSlop();
    }

    private void initAttrs(Context context, @Nullable AttributeSet attrs) {
        if (attrs == null) {
            return;
        }
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WheelPicker);

        mVisibleNumber = a.getInteger(R.styleable.WheelPicker_visibleNumber, mVisibleNumber);
        mCurrentPosition = a.getInteger(R.styleable.WheelPicker_currentPosition, mCurrentPosition);

        mSelectedColor = a.getColor(R.styleable.WheelPicker_selectedColor, mSelectedColor);
        mSelectedSize = a.getDimensionPixelSize(R.styleable.WheelPicker_selectedSize, mSelectedSize);

        mUnselectedColor = a.getColor(R.styleable.WheelPicker_unselectedColor, mUnselectedColor);
        mUnselectedPercent = a.getFloat(R.styleable.WheelPicker_unselectedSize, mUnselectedPercent);
        mUnselectedSize = (int) (mSelectedSize * mUnselectedPercent);

        mIsGradual = a.getBoolean(R.styleable.WheelPicker_isGradual, mIsGradual);

        mIsZoom = a.getBoolean(R.styleable.WheelPicker_isZoom, mIsZoom);

        mIsCyclic = a.getBoolean(R.styleable.WheelPicker_isCyclic, mIsCyclic);

        mIsCurtain = a.getBoolean(R.styleable.WheelPicker_isCurtain, mIsCurtain);
        mCurtainColor = a.getColor(R.styleable.WheelPicker_curtainColor, mCurtainColor);
        mIsCurtainBorder = a.getBoolean(R.styleable.WheelPicker_curtainBorder, mIsCurtainBorder);
        mCurtainBorderColor = a.getColor(R.styleable.WheelPicker_curtainBorderColor, mCurtainBorderColor);

        mIndicator = a.getString(R.styleable.WheelPicker_indicator);
        mIndicatorColor = a.getColor(R.styleable.WheelPicker_indicatorColor, mIndicatorColor);
        mIndicatorSize = a.getDimensionPixelSize(R.styleable.WheelPicker_indicatorSize, mIndicatorSize);
        a.recycle();
    }

    /**
     * 获取Item的宽高
     */
    public void computeTextSize() {
        mTextMaxWidth = mTextMaxHeight = 0;
        if (mDatas.size() == 0) {
            return;
        }

        //这里使用最大的,防止文字大小超过布局大小。
        mPaint.setTextSize(mSelectedSize > mUnselectedSize ? mSelectedSize : mUnselectedSize);

        /**
         * 计算最大的item控件的宽度
         */
        mTextMaxWidth = (int) mSelectedPaint.measureText(mDatas.get(0).toString()) + 20;

        /**
         * 计算最大的Item控件的高度
         */
        Paint.FontMetrics metrics = mPaint.getFontMetrics();
        mTextMaxHeight = (int) (metrics.bottom - metrics.top) + 20;
    }

    /**
     * 初始化画笔属性
     */
    private void initPaint() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setColor(mUnselectedColor);
        mTextPaint.setTextSize(mUnselectedSize);
        mSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG);
        mSelectedPaint.setStyle(Paint.Style.FILL);
        mSelectedPaint.setTextAlign(Paint.Align.CENTER);
        mSelectedPaint.setColor(mSelectedColor);
        mSelectedPaint.setTextSize(mSelectedSize);
        mIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG);
        mIndicatorPaint.setStyle(Paint.Style.FILL);
        mIndicatorPaint.setTextAlign(Paint.Align.CENTER);
        mIndicatorPaint.setColor(mIndicatorColor);
        mIndicatorPaint.setTextSize(mIndicatorSize);
    }

    /**
     *  计算实际的大小
     * @param specMode 测量模式
     * @param specSize 测量的大小
     * @param size     需要的大小
     * @return 返回的数值
     */
    private int measureSize(int specMode, int specSize, int size) {
        if (specMode == MeasureSpec.EXACTLY) {
            return specSize;
        } else {
            return Math.min(specSize, size);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int specWidthSize = MeasureSpec.getSize(widthMeasureSpec);
        int specWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        int specHeightSize = MeasureSpec.getSize(heightMeasureSpec);
        int specHeightMode = MeasureSpec.getMode(heightMeasureSpec);

        /**
         * 计算整个控件宽度
         */
        int width = mTextMaxWidth + getPaddingLeft() + getPaddingRight();

        /**
         * 计算控件高度
         * 20 为Item之间的间隔
         */
        int height = mTextMaxHeight * getVisibleItemCount() + getPaddingTop() + getPaddingBottom();

        /**
         * 重新绘制控件
         */
        setMeasuredDimension(measureSize(specWidthMode, specWidthSize, width),
                measureSize(specHeightMode, specHeightSize, height));
    }

    /**
     * 计算Fling极限
     * 如果为Cyclic模式则为Integer的极限值，如果正常模式，则为一整个数据集的上下限。
     */
    private void computeFlingLimitY() {
        mMinFlingY = mIsCyclic ? Integer.MIN_VALUE : - mItemHeight * (mDatas.size() - 1);
        mMaxFlingY = mIsCyclic ? Integer.MAX_VALUE : 0;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        /**
         * 控件实际可绘制面积（总面积 - 内边距）
         */
        mDrawnRect.set(getPaddingLeft(), getPaddingTop(),
                getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());

        /**
         * Item 的高度（可绘制高度 /  总条数）
         */
        mItemHeight = mDrawnRect.height() / getVisibleItemCount();

        /**
         * 获取X轴中心点坐标
         */
        mFirstItemDrawX = mDrawnRect.centerX();

        if (!TextUtils.isEmpty(mIndicator)) {
            mIndicatorDrawX = (int) (mDrawnRect.right - mIndicatorPaint.measureText(mIndicator) / 2) - 10;
        }

        /**
         * 获取第一个Item的Y轴坐标（Item高度 - （字体高度） / 2）
         */
        mFirstItemDrawY = (int) ((mItemHeight - (mSelectedPaint.ascent() + mSelectedPaint.descent())) / 2);

        /**
         * 中间的选中的Item的边框(除去内边距)
         * 上边框 坐标 = mItemHeight * mVisibleNumber（顶部未选择区域）
         * 下边框坐标 = mItemHeight + mItemHeight * mVisibleNumber （选中区域 + 底部未选择区域）
         */
        mSelectedRect.set(getPaddingLeft(), getPaddingTop() + mItemHeight * mVisibleNumber,
                getWidth() - getPaddingRight(), getPaddingBottom() + mItemHeight + mItemHeight * mVisibleNumber);
        computeFlingLimitY();

        /**
         * 选中区域的Y轴中心坐标 = 第一个Item Y轴中心坐标 + 顶部未选择区域高度
         */
        mCenterItemDrawnY = mFirstItemDrawY + mItemHeight * mVisibleNumber;
        mScrollOffsetY = - mItemHeight * mCurrentPosition;
    }

    /**
     * 修正坐标值，让其回到dates的范围内
     * @param position 修正前的值
     * @return  修正后的值
     */
    private int fixItemPosition(int position) {
        if (position < 0) {
            //将数据集限定在0 ~ mDatas.size()-1之间
            position = mDatas.size() + (position % mDatas.size());

        }
        if (position >= mDatas.size()){
            //将数据集限定在0 ~ mDatas.size()-1之间
            position = position % mDatas.size();
        }
        return position;
    }

    /**
     * 重绘
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        computeTextSize();
        computeFlingLimitY();

        mPaint.setTextAlign(Paint.Align.CENTER);

        drawCurtain(canvas);
        drawCurtainBorder(canvas);

        mPaint.setStyle(Paint.Style.FILL);

        drawData(canvas);

        drawIndicator(canvas);
    }

    /**
     * 绘制指示器
     * @param canvas
     */
    private void drawIndicator(Canvas canvas) {
        if (!TextUtils.isEmpty(mIndicator)) {
//            canvas.drawText(mIndicator, mFirstItemDrawX + mTextMaxWidth / 2, mCenterItemDrawnY, mIndicatorPaint);
            canvas.drawText(mIndicator, mIndicatorDrawX, mCenterItemDrawnY, mIndicatorPaint);
        }
    }

    /**
     * 绘制数据
     * @param canvas
     */
    private void drawData(Canvas canvas) {

        /**
         * 计算位移量,获取当前显示的数据下标（可见的第一个）
         */
        int drawnSelectedPos = - mScrollOffsetY / mItemHeight;

        /**
         * 首尾各多绘制一个用于缓冲
         */
        int min = drawnSelectedPos - mVisibleNumber - 1;
        int max = drawnSelectedPos + mVisibleNumber + 1;

        /**
         * 绘制数据
         */
        for (int drawDataPos = min; drawDataPos <= max; drawDataPos++) {
            int position = drawDataPos;
            /**
             * 数据是否循环
             */
            if (mIsCyclic) {
                position = fixItemPosition(position);
            } else {
                if (position < 0 || position > mDatas.size() - 1) {
                    continue;
                }
            }

            int itemDrawY = mFirstItemDrawY + (drawDataPos + mVisibleNumber) * mItemHeight + mScrollOffsetY;
            //距离中心的Y轴距离
            int distanceY = Math.abs(mCenterItemDrawnY - itemDrawY);

            initGradual(itemDrawY, distanceY);

            textZoom(distanceY);

            T data = mDatas.get(position);
            String drawText = getData(mDatas.get(position));
            // 在中间位置的Item作为被选中的。
            if (distanceY < mItemHeight / 2) {
                /**
                 * 绘制选中的Item
                 */
                canvas.drawText(drawText, mFirstItemDrawX, itemDrawY, mSelectedPaint);
            } else {
                /**
                 * 普通的
                 */
                canvas.drawText(drawText, mFirstItemDrawX, itemDrawY, mTextPaint);
            }
        }
    }

    /**
     * 获取对象值，填入控件中（非8种基本类型重写）
     * @param data
     * @return
     */
    public String getData(T data) {
        return mDataFormat == null ? data.toString() : mDataFormat.format(data);
    }

    /**
     * 开启渐变
     */
    private void initGradual(int itemDrawY, int distanceY) {
        if (mIsGradual) {
            //文字颜色渐变要在设置透明度上边，否则会被覆盖
            //计算文字颜色渐变
            if (distanceY < mItemHeight) {  //距离中心的高度小于一个ItemHeight才会开启渐变
                float colorRatio = 1 - (distanceY / (float) mItemHeight);
                mSelectedPaint.setColor(mLinearGradient.getColor(colorRatio));
                mTextPaint.setColor(mLinearGradient.getColor(colorRatio));
            } else {
                mSelectedPaint.setColor(mSelectedColor);
                mTextPaint.setColor(mUnselectedColor);
            }
            //计算透明度渐变
            float alphaRatio;
            if (itemDrawY > mCenterItemDrawnY) {
                alphaRatio = (mDrawnRect.height() - itemDrawY) /
                        (float) (mDrawnRect.height() - (mCenterItemDrawnY));
            } else {
                alphaRatio = itemDrawY / (float) mCenterItemDrawnY;
            }

            alphaRatio = alphaRatio < 0 ? 0 :alphaRatio;
            mSelectedPaint.setAlpha((int) (alphaRatio * 255));
            mTextPaint.setAlpha((int) (alphaRatio * 255));
        }
    }

    /**
     * 数据缩放
     * @param distanceY
     */
    private void textZoom(int distanceY) {
        /**
         * 开启此选项,会将越靠近中心的Item字体放大
         */
        if (mIsZoom) {
            if (distanceY < mItemHeight) {
                float addedSize = (mItemHeight - distanceY) / (float) mItemHeight
                        * (mSelectedSize - mUnselectedSize);
                mSelectedPaint.setTextSize(mUnselectedSize + addedSize);
                mTextPaint.setTextSize(mUnselectedSize + addedSize);
            } else {
                mSelectedPaint.setTextSize(mUnselectedSize);
                mTextPaint.setTextSize(mUnselectedSize);
            }
        } else {
            mSelectedPaint.setTextSize(mUnselectedSize);
            mTextPaint.setTextSize(mUnselectedSize);
        }
    }

    /**
     * 绘制幕布
     * @param canvas
     */
    private void drawCurtain(Canvas canvas) {
        if (mIsCurtain) {
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(mCurtainColor);
            canvas.drawRect(mSelectedRect, mPaint);
        }
    }

    /**
     * 绘制幕布边框
     * @param canvas
     */
    private void drawCurtainBorder(Canvas canvas) {
        /**
         * 是否存在幕布边框
         */
        if (mIsCurtainBorder) {
            mPaint.setStrokeWidth(2);
            mPaint.setColor(mCurtainBorderColor);
            canvas.drawLine(mSelectedRect.left, mSelectedRect.top,
                    mSelectedRect.right, mSelectedRect.top, mPaint);// 画线
            canvas.drawLine(mSelectedRect.left, mSelectedRect.bottom,
                    mSelectedRect.right, mSelectedRect.bottom, mPaint);// 画线
//            canvas.drawRect(mSelectedRect, mPaint);
//            canvas.drawRect(mDrawnRect, mPaint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (mDatas == null || mDatas.size() == 0) {
            return false;
        }

        if (mTracker == null) {
            mTracker = VelocityTracker.obtain();
        }
        mTracker.addMovement(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                    mIsAbortScroller = true;
                } else {
                    mIsAbortScroller = false;
                }
                mTracker.clear();
                mTouchDownY = mLastDownY = (int) event.getY();
                mTouchSlopFlag = true;
                break;
            case MotionEvent.ACTION_MOVE:
                if (mTouchSlopFlag && Math.abs(mTouchDownY - event.getY()) < mTouchSlop) {
                    break;
                }
                mTouchSlopFlag = false;
                float move = event.getY() - mLastDownY;
                mScrollOffsetY += move;
                mLastDownY = (int) event.getY();
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                if (!mIsAbortScroller && mTouchDownY == mLastDownY) {
                    performClick();
                    if (event.getY() > mSelectedRect.bottom) {
                        int scrollItem = (int) (event.getY() - mSelectedRect.bottom) / mItemHeight + 1;
                        mScroller.startScroll(0, mScrollOffsetY, 0,
                                -scrollItem * mItemHeight);

                    } else if (event.getY() < mSelectedRect.top) {
                        int scrollItem = (int) (mSelectedRect.top - event.getY()) / mItemHeight + 1;
                        mScroller.startScroll(0, mScrollOffsetY, 0,
                                scrollItem * mItemHeight);
                    }
                } else {
                    mTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                    int velocity = (int) mTracker.getYVelocity();
                    if (Math.abs(velocity) > mMinimumVelocity) {
                        mScroller.fling(0, mScrollOffsetY, 0, velocity,
                                0, 0, mMinFlingY, mMaxFlingY);
                        mScroller.setFinalY(mScroller.getFinalY() +
                                computeDistanceToEndPoint(mScroller.getFinalY() % mItemHeight));
                    } else {
                        mScroller.startScroll(0, mScrollOffsetY, 0,
                                computeDistanceToEndPoint(mScrollOffsetY % mItemHeight));
                    }
                }
                if (!mIsCyclic) {
                    if (mScroller.getFinalY() > mMaxFlingY) {
                        mScroller.setFinalY(mMaxFlingY);
                    } else if (mScroller.getFinalY() < mMinFlingY) {
                        mScroller.setFinalY(mMinFlingY);
                    }
                }
                mHandler.post(mScrollerRunnable);
                mTracker.recycle();
                mTracker = null;
                break;
        }
        return true;
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    private int computeDistanceToEndPoint(int remainder) {
        if (Math.abs(remainder) > mItemHeight / 2) {
            if (mScrollOffsetY < 0) {
                return -mItemHeight - remainder;
            } else {
                return mItemHeight - remainder;
            }
        } else {
            return -remainder;
        }
    }


    public void setOnWheelChangeListener(OnWheelChangeListener<T> onWheelChangeListener) {
        mOnWheelChangeListener = onWheelChangeListener;
    }

    public Paint getTextPaint() {
        return mTextPaint;
    }

    public Paint getSelectedItemPaint() {
        return mSelectedPaint;
    }

    public Paint getPaint() {
        return mPaint;
    }

    public Paint getIndicatorPaint() {
        return mIndicatorPaint;
    }

    /**
     * 获取数据
     * @return
     */
    public List<T> getDatas() {
        return mDatas;
    }

    /**
     * 设置数据
     * @param datas
     */
    public void setData(@NonNull List<T> datas) {
        if (datas == null || datas.size() == 0) {
            return;
        }
        mDatas.clear();
        mDatas.addAll(datas);
        postInvalidate();
    }

    /**
     * 设置数据 及 默认显示位置
     * @param datas
     * @param currentPosition
     */
    public void setData(@NonNull List<T> datas, int currentPosition) {
        if (datas == null || datas.size() == 0) {
            return;
        }
        mDatas.clear();
        mDatas.addAll(datas);
        postInvalidate();
        setCurrentPosition(currentPosition);
    }

    public int getUnselectedColor() {
        return mUnselectedColor;
    }

    /**
     * 一般列表的文本颜色
     * @param textColor 文本颜色
     */
    public void setUnselectedColor(@ColorInt int textColor) {
        if (mUnselectedColor == textColor) {
            return;
        }
        mTextPaint.setColor(textColor);
        mUnselectedColor = textColor;
        mLinearGradient.setStartColor(textColor);
        postInvalidate();
    }

    public int getUnselectedSize() {
        return mUnselectedSize;
    }

    /**
     * 一般列表的文本大小
     * @param textSize 文字大小
     */
    public void setUnselectedSize(int textSize) {
        if (mUnselectedSize == textSize) {
            return;
        }
        mUnselectedSize = textSize;
        mTextPaint.setTextSize(textSize);
        computeTextSize();
        postInvalidate();
    }

    public int getSelectedColor() {
        return mSelectedColor;
    }

    /**
     * 设置被选中时候的文本颜色
     * @param selectedColor 文本颜色
     */
    public void setSelectedColor(@ColorInt int selectedColor) {
        if (mSelectedColor == selectedColor) {
            return;
        }
        mSelectedPaint.setColor(selectedColor);
        mSelectedColor = selectedColor;
        mLinearGradient.setEndColor(selectedColor);
        postInvalidate();
    }

    public int getSelectedSize() {
        return mSelectedSize;
    }

    /**
     * 设置被选中时候的文本大小
     * @param selectedSize 文字大小
     */
    public void setSelectedSize(int selectedSize) {
        if (mSelectedSize == selectedSize) {
            return;
        }
        mSelectedPaint.setTextSize(selectedSize);
        mSelectedSize = selectedSize;
        computeTextSize();
        postInvalidate();
    }


    public int getVisibleNumber() {
        return mVisibleNumber;
    }

    /**
     * 显示的个数等于上下两边Item的个数+ 中间的Item
     * @return 总显示的数量
     */
    public int getVisibleItemCount() {
        return mVisibleNumber * 2 + 1;
    }

    /**
     * 设置显示数据量的个数的一半。
     * 为保证总显示个数为奇数,这里将总数拆分，总数为 mVisibleNumber * 2 + 1
     * @param mVisibleNumber 总数量的一半
     */
    public void setVisibleNumber(int mVisibleNumber) {
        if (this.mVisibleNumber == mVisibleNumber) {
            return;
        }
        this.mVisibleNumber = mVisibleNumber;
        requestLayout();
    }

    public int getCurrentPosition() {
        return mCurrentPosition;
    }

    /**
     * 设置当前选中的列表项,将滚动到所选位置
     * @param currentPosition 设置的当前位置
     */
    public void setCurrentPosition(int currentPosition) {
        setCurrentPosition(currentPosition, true);
    }

    /**
     * 设置当前选中的列表位置
     * @param currentPosition 设置的当前位置
     * @param smoothScroll 是否平滑滚动
     */
    public synchronized void setCurrentPosition(int currentPosition, boolean smoothScroll) {
        if (currentPosition > mDatas.size() - 1) {
            currentPosition = mDatas.size() - 1;
        }
        if (currentPosition < 0) {
            currentPosition = 0;
        }
        if (mCurrentPosition == currentPosition) {
            return;
        }
        if (!mScroller.isFinished()) {
            mScroller.abortAnimation();
        }

        //如果mItemHeight=0代表还没有绘制完成，这时平滑滚动没有意义
        if (smoothScroll && mItemHeight > 0) {
            mScroller.startScroll(0, mScrollOffsetY, 0, (mCurrentPosition - currentPosition) * mItemHeight);
//            mScroller.setFinalY(mScroller.getFinalY() +
//                    computeDistanceToEndPoint(mScroller.getFinalY() % mItemHeight));
            int finalY = -currentPosition * mItemHeight;
            mScroller.setFinalY(finalY);
            mHandler.post(mScrollerRunnable);
        } else {
            mCurrentPosition = currentPosition;
            mScrollOffsetY = -mItemHeight * mCurrentPosition;
            postInvalidate();
            if (mOnWheelChangeListener != null) {
                mOnWheelChangeListener.onWheelSelected(mDatas.get(currentPosition), currentPosition);
            }
        }
    }

    public boolean isZoom() {
        return mIsZoom;
    }

    /**
     * 设置是否放大选中项
     * @param zoom
     */
    public void setZoom(boolean zoom) {
        if (mIsZoom == zoom) {
            return;
        }
        mIsZoom = zoom;
        postInvalidate();
    }

    public boolean isCyclic() {
        return mIsCyclic;
    }

    /**
     * 设置是否循环滚动。
     * @param cyclic 上下边界是否相邻
     */
    public void setCyclic(boolean cyclic) {
        if (mIsCyclic == cyclic) {
            return;
        }
        mIsCyclic = cyclic;
        computeFlingLimitY();
        requestLayout();
    }

    public int getMinimumVelocity() {
        return mMinimumVelocity;
    }

    /**
     * 设置最小滚动速度,如果实际速度小于此速度，将不会触发滚动。
     * @param minimumVelocity 最小速度
     */
    public void setMinimumVelocity(int minimumVelocity) {
        mMinimumVelocity = minimumVelocity;
    }

    public int getMaximumVelocity() {
        return mMaximumVelocity;
    }

    /**
     * 设置最大滚动的速度,实际滚动速度的上限
     * @param maximumVelocity 最大滚动速度
     */
    public void setMaximumVelocity(int maximumVelocity) {
        mMaximumVelocity = maximumVelocity;
    }

    public boolean isGradual() {
        return mIsGradual;
    }

    /**
     * 设置文字渐变，离中心越远越淡。
     * @param gradual 是否渐变
     */
    public void setGradual(boolean gradual) {
        if (mIsGradual == gradual) {
            return;
        }
        mIsGradual = gradual;
        postInvalidate();
    }

    public boolean isCurtain() {
        return mIsCurtain;
    }

    /**
     * 设置中心Item是否有幕布遮盖
     * @param isCurtain 是否有幕布
     */
    public void setCurtain(boolean isCurtain) {
        if (mIsCurtain == isCurtain) {
            return;
        }
        mIsCurtain = isCurtain;
        postInvalidate();
    }

    public int getCurtainColor() {
        return mCurtainColor;
    }

    /**
     * 设置幕布颜色
     * @param curtainColor 幕布颜色
     */
    public void setCurtainColor(@ColorInt int curtainColor) {
        if (mCurtainColor == curtainColor) {
            return;
        }
        mCurtainColor = curtainColor;
        postInvalidate();
    }

    public boolean isCurtainBorder() {
        return mIsCurtainBorder;
    }

    /**
     * 设置幕布是否显示边框
     * @param showCurtainBorder 是否有幕布边框
     */
    public void setCurtainBorder(boolean showCurtainBorder) {
        if (mIsCurtainBorder == showCurtainBorder) {
            return;
        }
        mIsCurtainBorder = showCurtainBorder;
        postInvalidate();
    }

    public int getCurtainBorderColor() {
        return mCurtainBorderColor;
    }

    /**
     * 幕布边框的颜色
     * @param curtainBorderColor 幕布边框颜色
     */
    public void setCurtainBorderColor(@ColorInt int curtainBorderColor) {
        if (mCurtainBorderColor == curtainBorderColor) {
            return;
        }
        mCurtainBorderColor = curtainBorderColor;
        postInvalidate();
    }

    public void setIndicator(String indicatorText) {
        mIndicator = indicatorText;
        postInvalidate();
    }

    public void setIndicatorColor(int indicatorTextColor) {
        mIndicatorColor = indicatorTextColor;
        mIndicatorPaint.setColor(mIndicatorColor);
        postInvalidate();
    }

    public void setIndicatorSize(int indicatorTextSize) {
        mIndicatorSize = indicatorTextSize;
        mIndicatorPaint.setTextSize(mIndicatorSize);
        postInvalidate();
    }

    /**
     * 设置数据集格式
     * @param dataFormat 格式
     */
    public void setDataFormat(Format dataFormat) {
        mDataFormat = dataFormat;
        postInvalidate();
    }

    public Format getDataFormat() {
        return mDataFormat;
    }

    public interface OnWheelChangeListener<T> {
        void onWheelSelected(T data, int position);
    }
}
